package cn.mjnxin.iot.transfer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

import cn.mjnxin.iot.base.handle.IHolderHanders;
import cn.mjnxin.iot.base.log.LogWorker;
import cn.mjnxin.iot.base.util.CommonUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * 网关的监视狗
 * @author CLG 2023年10月10日
 * @version V1.0.0
 */
@Sharable
public abstract class ConnectionWacthDog extends SimpleChannelInboundHandler<Object> implements IHolderHanders{
    private final Bootstrap bootstrap;

    private Channel   channel        = null;
    
    private Integer   gateNo;
    private Integer   pid;
    private String    serverAddress;
    private Integer   serverPort;
    private boolean   flag; // 是否执行重试机制
    private Relogin   redoLogin;
    private String    localAddress   = null;
    
    private final static Long timeMillis = 5000L;
    
    public static interface Relogin{
    	/**
    	 * 一端向另一端登录鉴权的字节信息
    	 * @param gateNo
    	 * @param pid
    	 * @param LocalAddress
    	 * @return 返回null则无需登录鉴权
    	 * @throws Exception
    	 */
        ByteBuf getLoginBuf(Integer gateNo, Integer pid, String LocalAddress) throws Exception;
        
        void onConnectSuccess(String ip, Integer port, Integer pid);
        
        void onConnectFailed(String ip, Integer port, Integer pid);
    }
    
    public String getLocalAddress() {
        return localAddress;
    }
    
    /**
     * 连接服务端 and 重连
     * @throws IOException 
     */
    public void doConnect() {
        if (channel != null && channel.isActive()){
            return;
        }
//            String localIP = MixAll.localIP();
//            System.out.println("localIP:" + localIP);
//            int localAvailablePort = MixAll.localAvailablePort();
//            System.out.println("localAvailablePort:" + localAvailablePort);
//        	bootstrap.remoteAddress(new InetSocketAddress(localIP, localAvailablePort));
        ChannelFuture connect = bootstrap.connect(serverAddress, serverPort);
//	        ChannelFuture connect = bootstrap.connect().sync();
	        
        //实现监听通道连接的方法
        connect.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if(channelFuture.isSuccess()){
                    channel = channelFuture.channel();
                    /**
                     * 连接成功之后 发送登录信息
                     */
                    InetSocketAddress localSocket = (InetSocketAddress) channel.localAddress();
                    LogWorker.logForce("localAddress:" + localSocket);
                    InetSocketAddress gateSocket = (InetSocketAddress) channel.remoteAddress();
                    LogWorker.logForce("remoteAddress:" + channel.remoteAddress());
                    
                    localAddress = CommonUtil.getIpAddress(localSocket);
                    String gateAddress = CommonUtil.getIpAddress(gateSocket);
                    ByteBuf buf = redoLogin.getLoginBuf(gateNo, pid, localAddress);
                    if (buf != null) {
                        LogWorker.logForce(String.format("%d|Local[%s]->G[%s]=", pid, localAddress, gateAddress), buf);
                        channel.writeAndFlush(buf);
                    }
                    redoLogin.onConnectSuccess(serverAddress, serverPort, pid);
                }else{
                    localAddress = null;
                	channelFuture.cause().printStackTrace();
                    redoLogin.onConnectFailed(serverAddress, serverPort, pid);
                    channelFuture.channel().eventLoop().schedule(new Runnable() {
                        @Override
                        public void run() {
							doConnect();
                        }
                    }, timeMillis, TimeUnit.MILLISECONDS);
                }
            }
        });
    }

    /**
     * @param bootstrap 引导
     * @param serverAddress 前置IP
     * @param serverPort 前置端口
     * @param timer 定时器
     * @param flag 是否执行重试机制
     */
    public ConnectionWacthDog(Integer gateNo, Integer pid, String serverAddress, Integer serverPort, boolean flag, Relogin redoLogin) {
        super();
        this.bootstrap = new Bootstrap();
        this.gateNo = gateNo;
        this.pid = pid;
        this.serverAddress = serverAddress;
        this.serverPort = serverPort;
        this.flag = flag;
        this.redoLogin = redoLogin;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelInactive();
        if(flag){
            channel = null;
            doConnect();
        }
    }

	public Bootstrap getBootstrap() {
		return bootstrap;
	}

	public Integer getGateNo() {
		return gateNo;
	}

	public void setGateNo(Integer gateNo) {
		this.gateNo = gateNo;
	}
}
